/**
 * 
 */
package com.trungsi.profile;

import java.util.Comparator;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author ductrung.tran
 *
 */
public class NotifTracker {

	String notifId;
	
	ConcurrentMap<String, Time> timeMap = new ConcurrentHashMap<String, Time>();
	
	AtomicLong firstStart = new AtomicLong();
	
	public NotifTracker(String notifId) {
		this.notifId = notifId;
	}

	public void begin(String traceName) {
		if (timeMap.containsKey(traceName)) {
			traceName += "2";
			if (timeMap.containsKey(traceName)) {
				throw new RuntimeException("Method " + traceName + " called more than twice for notif " + notifId);
			}
		}
		
		Time time = new Time(traceName);
		timeMap.put(traceName, time);
		firstStart.compareAndSet(0, time.start);
	}

	public void end(String traceName) {
		Time time = timeMap.get(traceName);
		if (time == null) {
			throw new RuntimeException("Method " + traceName + " has lost the beginning for notif " + notifId);
		}
		
		if (time.isEnded()) {
			traceName += "2";
			time = timeMap.get(traceName);
			if (time == null) {
				throw new RuntimeException("Method " + traceName + " has lost the beginning for notif " + notifId);
			}
		}
		
		time.end();
	}

	public String toString() {
		TreeSet<Time> times = new TreeSet<Time>(new Comparator<Time>() {

			//@Override
			public int compare(Time o1, Time o2) {
				return o1.start < o2.start ? -1 :
							o1.start > o2.start ? 1 : 0;
			}});
		times.addAll(timeMap.values());
		
		StringBuilder builder = new StringBuilder(notifId);
		long end = 0;
		for (Time time : times) {
			builder.append(",").append(time.traceName).append("=").append(time.time());
			end = Math.max(end, time.end);
		}
		builder.append(",total=").append(end - firstStart.longValue());
		
		return builder.toString();
	}
	
	static class Time {

		String traceName;
		long start;
		long end;
		
		public Time(String traceName) {
			this.traceName = traceName;
			start = System.currentTimeMillis();
		}

		public void end() {
			end = System.currentTimeMillis();
			
		}

		public boolean isEnded() {
			return end > 0;
		}
		
		public long time() {
			return end - start;
		}
	}
}
